"""CRC calcualtion functions.

In theory, only calccrc is needed externally."""
import math
import time

def pad_with_0(crc,polynomLength):
    crcStr = bin(crc)[2:]
    while len(crcStr)< polynomLength:
        crcStr = '0' + crcStr
    return crcStr

def calccrc(data,polynom = 0b1101):
    """Calculate the CRC with the bytes given in data.

    polynom : The generator polynom. It is given as an int. The bits at 1
    are the coeficiented ones.
    Default value : 1101.
    data : A generator giving the bits (one by one) to add to the CRC.

    The function returns the bits of the CRC, as an integer."""
    polynomLength = int(math.log(polynom, 2))
    crc = 0
    for i in data:
        assert i is 0 or i is 1
        crc = crc << 1
        crc = crc + i
        if crc >= (1 << polynomLength):
            crc = (crc ^ polynom)
        crc = crc % (1 << polynomLength)
    
    return pad_with_0(crc,polynomLength)


def calccrc_with_log(data, polynom, resultFrame):
    """Calculate the CRC with the bytes given in data.

    polynom : The generator polynom. It is given as an int. The bits at 1
    are the coeficiented ones.
    Default value : 1101.
    data : A generator giving the bits (one by one) to add to the CRC.

    The function returns the bits of the CRC, as an integer."""

    
    polynomLength = int(math.log(polynom, 2))
    
    def loopOnce(crc,i):
        """Performs one loop of the crc calculation.

        Returns the updated CRC."""
        crc = crc << 1
        crc = crc + i
        if crc >= (1 << polynomLength):
            crc = (crc ^ polynom)
        crc = crc % (1 << polynomLength)
        return crc
    crc = 0
    
    crcStr = pad_with_0(crc,polynomLength)
    
    for i in data:
        assert i is 0 or i is 1

        crcStr = crcStr + str(i)
        with resultFrame.allLock:
            resultFrame.crcCurrentCalculated = crcStr
        
        crc = crc << 1
        crc = crc + i
        if crc >= (1 << polynomLength):
            crc = (crc ^ polynom)
        crc = crc % (1 << polynomLength)
        
        crcStr = pad_with_0(crc,polynomLength)

    crcStr = crcStr + " "
    with resultFrame.allLock:
        resultFrame.crcCurrentCalculated = crcStr
    
    
    return pad_with_0(crc,polynomLength)
